///////////////////////////////////////////////////////////////////////////
////                             LCDD.C                                ////
////                 Driver for common LCD modules                     ////
////                                                                   ////
////  lcd_init()   Must be called before any other function.           ////
////                                                                   ////
////  lcd_putc(c)  Will display c on the next position of the LCD.     ////
////                     The following have special meaning:           ////
////                      \f  Clear display                            ////
////                      \n  Go to start of second line               ////
////                      \b  Move back one position                   ////
////                                                                   ////
////  lcd_gotoxy(x,y) Set write position on LCD (upper left is 1,1)    ////
////                                                                   ////
////  lcd_getc(x,y)   Returns character at position x,y on LCD         ////
////                                                                   ////
///////////////////////////////////////////////////////////////////////////
////        (C) Copyright 1996,2007 Custom Computer Services           ////
//// This source code may only be used by licensed users of the CCS C  ////
//// compiler.  This source code may only be distributed to other      ////
//// licensed users of the CCS C compiler.  No other use, reproduction ////
//// or distribution is permitted without written permission.          ////
//// Derivative programs created using this software in object code    ////
//// form are not restricted in any way.                               ////
///////////////////////////////////////////////////////////////////////////

// As defined in the following structure the pin connection is as follows:

#define set_tris_lcd(x) TRISB = x;
#define rs      RB7
#define rw      RB6
#define enable  RB5
#define D4      RB4
#define D5      RB3
#define D6      RB2
#define D7      RB1
#define data    (D4 | D5 << 1 | D6 << 2 | D7 << 3 )
//
//   LCD pins D0-D3 are not used and PIC D3 is not used.

// Un-comment the following define to use port B
// #define use_portb_lcd TRUE


//struct lcd_pin_map {                 // This structure is overlayed
//           T_UBYTE  enable  : 1;           // on to an I/O port to gain
//           T_UBYTE  rs      : 1;               // access to the LCD pins.
//           T_UBYTE  rw      : 1;               // The bits are allocated from
//           T_UBYTE  unused  : 1;           // low order up.  ENABLE will
//           T_UBYTE  data    : 4;         // be pin B0.
//        } lcd;
#include "stdtypedef.h"
#include "system.h"
#include "LCD.h"

#ifndef lcd_type
#define lcd_type 2           // 0=5x7, 1=5x10, 2=2 lines
#endif

#define lcd_line_two 0x40    // LCD RAM address for the second line
#define delay_cycles(x)     delay_ms(x)


T_UBYTE const LCD_INIT_STRING[4] = {0x20 | (lcd_type << 2), 0xc, 1, 6};
                             // These bytes need to be sent to the LCD
                             // to start it up.


                             // The following are used for setting
                             // the I/O port direction register.

//struct lcd_pin_map const LCD_WRITE = {0,0,0,0,0}; // For write mode all pins are out
//struct lcd_pin_map const LCD_READ = {0,0,0,0,15}; // For read mode data pins are in



T_UBYTE lcd_read_byte() {
      T_UBYTE low,high;
      set_tris_lcd(0xF0);
      rw = 1;
      delay_cycles(1);
      enable = 1;
      delay_cycles(1);
      high = data;
      enable = 0;
      delay_cycles(1);
      enable = 1;
      delay_ms(1);
      low = data;
      enable = 0;
      set_tris_lcd(0);
      return( (high<<4) | low);
}


void lcd_send_nibble( T_UBYTE n ) {
      D4 = (n & 0x01);
      D5 = (n >> 1 & 0x01);
      D6 = (n >> 2 & 0x01);
      D7 = (n >> 3 & 0x01);
      delay_cycles(1);
      enable = 1;
      delay_ms(2);
      enable = 0;
}


void lcd_send_byte( T_UBYTE address, T_UBYTE n ) {

//      rs = 0;
//      while ( bit_test(lcd_read_byte(),7) ) ;
      rs = address;
      delay_cycles(1);
      rw = 0;
      delay_cycles(1);
      enable = 0;
      lcd_send_nibble(n >> 4);
      lcd_send_nibble(n & 0xf);
}


void lcd_init() {
    T_UBYTE i;
    set_tris_lcd(0);	//Configuracion de puertos
    rs = 0;					
    rw = 0;
    enable = 0;
    delay_ms(15);				//Espera 15 milisegundos
    for(i=1;i<=3;++i) {
       lcd_send_nibble(3);
       delay_ms(5);
    }
    lcd_send_nibble(2);
    for(i=0;i<=3;++i)
       lcd_send_byte(0,LCD_INIT_STRING[i]);
}


void lcd_gotoxy( T_UBYTE x, T_UBYTE y) {
   T_UBYTE address;

   if(y != 1)
     address = lcd_line_two;
   else
     address=0;
   address += x-1;
   lcd_send_byte(0,0x80|address);
}

void lcd_putc( char lcd_char) {
   switch (lcd_char) {
     case '\f'   : lcd_send_byte(0,1);
                   delay_ms(2);
                                           break;
     case '\n'   : lcd_gotoxy(1,2);        break;
     case '\b'   : lcd_send_byte(0,0x10);  break;
     default     : lcd_send_byte(1,lcd_char);     break;
   }
}

char lcd_getc( T_UBYTE x, T_UBYTE y) {
   char value;

    lcd_gotoxy(x,y);
//    while ( bit_test(lcd_read_byte(),7) ); // wait until busy flag is low
    rs=1;
    value = lcd_read_byte();
    rs=0;
    return(value);
}

void delay_ms(T_UWORD t){
    T_UWORD i;
    for(i = 0; i < t*(T_UWORD)(FCY/100000U); i++){
        asm("nop");
    }
}

void lcd_print(T_UBYTE  data_print[]){
    T_UBYTE n = 0;
    for(n = 0; data_print[n] != 0; n++){
        lcd_putc(data_print[n]);
    }
}